package cn.bo.cloud.demo2.web;


import cn.bo.cloud.demo2.domain.dto.User;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

/**
 * 注解方式配置sentinel流控
 */

@RestController
@RequestMapping("/server2")
public class ServerController2 {

    @Value("${server.port}")
    String port;

    private static final String RESOURCE_NAME = "s2uri1";

    /**
     * @SentinelResource 改善接口中资源定义和被流控降级后的处理方法
     * 怎么使用： 1. 添加依赖<artifactId>sentinel-annotation-aspectj</artifactId>
     *             2. 配置bean--SentinelResourceAspect
     *
     * value 定义资源
     * blockHandler 设置流量降级后处理方法（默认该方法必须和原方法声明在同一个类中）
     *      如果不想在同一个类，可以设置blockHandlerClass  ,不过需要注意，函数必须声明为static
     * fallback 当接口出现了异常，就可以交给fallback处理
     * ps: blockHandler和fallback同时指定的话，blockHandler优先级更高
     * exceptionsToIgnore 排除哪些异常不处理
     * @return
     */
    @RequestMapping("/s2uri1")
    @SentinelResource(value = RESOURCE_NAME,
            blockHandler = "blockHandlerForGetUser",
            fallback = "fallbackHandlerForGetUser"
    )
    public User test01(){
//        int a = 1/0;
        return new User("server2-u1-" + port);

    }

    /**
     * 1. 一定要public
     * 2. 返回值一定要和原方法保证一致
     * 3. 可以在参数最后添加BlockException 可以区分是什么规则的异常处理方法
     * @param ex
     * @return
     */
    public User blockHandlerForGetUser(BlockException ex){
//        ex.printStackTrace();
//        fl.printStackTrace();
        return new User("被流控了");
    }

    public User fallbackHandlerForGetUser(Throwable throwable){
//        ex.printStackTrace();
//        fl.printStackTrace();
        return new User("异常处理");
    }

    @PostConstruct
    private static void initFlowRules(){
        // 流控规则
        List<FlowRule> rules = new ArrayList<>();

        // 流控
        FlowRule rule = new FlowRule();
        // 设置受保护的资源
        rule.setResource(RESOURCE_NAME);
        // 设置流控规则QPS 或者线程数 （2种规则）
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 设置受保护的资源阈值
        // set limit QPS to 20.
        rule.setCount(1);
        rules.add(rule);

        FlowRuleManager.loadRules(rules);

        // 通过@SentinelResource来定义资源
    }

}
